using System;
using System.Collections;
using Life.ESound.Bridge;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Serialization;
using EffectTypeValue = System.Int32;
using BgmTypeValue = System.Int32;

namespace Life.ESound
{
    /// <summary>
    /// 声音控制器
    /// </summary>
    public class SoundController : MonoBehaviour
    {
        [SerializeField]bool defaultPlayBgm = false;
        [SerializeField]bool actionOnFocus = true;
        [SerializeField]
        private float mainVolume = 1.0f;
        [SerializeField]
        private float bgmVolume = 1f;
        [SerializeField]
        private float effectVolume = 1f;
        
        [SerializeField][ShowIf("defaultPlayBgm")][BgmSelect] BgmTypeValue defaultBgm;
        private static SoundController _instance;
        public static SoundController Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = FindObjectOfType<SoundController>();
                    if (_instance == null)
                    {
                        GameObject obj = new GameObject
                        {
                            name = "SoundController"
                        };
                        _instance = obj.AddComponent<SoundController>();
                    }
                }
                return _instance;
            }
        }
        
        private AudioSource _effectAudioSource;
        
        private SoundClips _soundClips;

        private ESoundBridge _bridge;
        
        private BgmAudioPlayer _bgmAudioPlayer;

        
        private float _internalVolumeScale = 1.0f;
        
        public bool BgmIsPlaying => _bgmAudioPlayer!=null && _bgmAudioPlayer.IsPlaying;
        public bool BgmIsPause => _bgmAudioPlayer!=null && _bgmAudioPlayer.IsPaused;
        
        public float MainVolume
        {
            get=>mainVolume;
            set
            {
                mainVolume = value;
                _bgmAudioPlayer.volume = mainVolume * bgmVolume;
                _effectAudioSource.volume = mainVolume * effectVolume;
            }
        }
        public float EffectVolume
        {
            get => effectVolume;
            set
            {
                effectVolume = value;
                _effectAudioSource.volume = mainVolume * effectVolume;
            }
        }
        
        public float BgmVolume
        {
            get => bgmVolume;
            set
            {
                bgmVolume = value;
                _bgmAudioPlayer.volume = mainVolume * bgmVolume;
            }
        }

        private void Awake()
        {
            if (_instance == null)
            {
                _instance = this;
            }
            else if (_instance != this)
            {
                Destroy(gameObject);
            }
            
            _effectAudioSource = gameObject.AddComponent<AudioSource>();
            
            _bgmAudioPlayer = gameObject.GetComponent<BgmAudioPlayer>();
            if (_bgmAudioPlayer == null)
                _bgmAudioPlayer = gameObject.AddComponent<BgmAudioPlayer>();
            _bgmAudioPlayer.audioSource = gameObject.AddComponent<AudioSource>();
            SetBgmVolume();
            
            _effectAudioSource.volume = mainVolume * effectVolume;
            _soundClips = Resources.Load<SoundClips>("SoundClips");
            _soundClips.Initialize();
            
            if (defaultPlayBgm)
            {
                PlayBgm(defaultBgm, true);
            }

            _bridge = gameObject.GetComponent<ESoundBridge>();
            if (_bridge == null)
                _bridge = gameObject.AddComponent<ESoundBridge>();
            if (_bridge != null)
            {
                _bridge.OnMainVolumeChange.AddListener(SetMainVolume);
                _bridge.OnEffectVolumeChange.AddListener(SetEffectVolume);
                _bridge.OnBgmVolumeChange.AddListener(SetBgmVolume);
                _bridge.MainVolumeGetter = () => MainVolume;
                _bridge.EffectVolumeGetter = () => EffectVolume;
                _bridge.BgmVolumeGetter = () => BgmVolume;
                
                _bridge.BgmIsPlayerGetter = ()=> BgmIsPlaying;
                _bridge.BgmIsPauseGetter  = ()=> BgmIsPause;
                _bridge.StopBgmRef = StopBgm;
                _bridge.PauseBgmRef = PauseBgm;
                _bridge.ResumeBgmRef = ResumeBgm;
                _bridge.StopBgmRefIntAction = StopBgm;
                _bridge.PauseBgmRefIntAction = PauseBgm;
                _bridge.ResumeBgmRefIntAction = ResumeBgm;

                _bridge.PlayEffectMethodRefInt = PlayEffect;
                _bridge.PlayEffectMethodRefClip = PlayEffect;
                _bridge.PlayEffectMethodRefIntVolume = PlayEffect;
                _bridge.PlayEffectMethodRefClipVolume = PlayEffect;
                _bridge.PlayBgmMethodRefInt = PlayBgm;
                _bridge.PlayBgmMethodRefClip = PlayBgm;
                _bgmAudioPlayer.OnFinished.AddListener(_bridge.OnBgmComplete.Invoke);

                _bridge.Initialized();
            }
        }

        private void SetBgmVolume()
        {
            _bgmAudioPlayer.volume = mainVolume * bgmVolume;
        }
        
        public void SetMainVolume(float volume)
        {
            MainVolume = volume;
        }

        public void SetEffectVolume(float volume)
        {
            EffectVolume = volume;
        }

        public void SetBgmVolume(float volume)
        {
            BgmVolume = volume;
        }
        
        /// <summary>
        /// 播放一个声音
        /// </summary>
        /// <param name="type"></param>
        public void PlayEffect(EffectTypeValue type)
        {
            AudioClip clip = _soundClips.GetEffectClip(type);
            if (clip != null)
            {
                _effectAudioSource.PlayOneShot(clip);
            }
        }
        /// <summary>
        /// 播放一个声音
        /// </summary>
        /// <param name="clip"></param>
        public void PlayEffect(AudioClip clip)
        {
            if (clip != null)
            {
                _effectAudioSource.PlayOneShot(clip);
            }
        }
        /// <summary>
        /// 播放一个声音
        /// </summary>
        /// <param name="type"></param>
        /// <param name="exVolume"></param>
        public void PlayEffect(EffectTypeValue type,float exVolume)
        {
            AudioClip clip = _soundClips.GetEffectClip(type);
            if (clip != null)
            {
                _effectAudioSource.PlayOneShot(clip,exVolume);
            }
        }
        /// <summary>
        /// 播放一个声音
        /// </summary>
        /// <param name="clip"></param>
        /// <param name="exVolume"></param>
        public void PlayEffect(AudioClip clip,float exVolume)
        {
            if (clip != null)
            {
                _effectAudioSource.PlayOneShot(clip,exVolume);
            }
        }

        public void PlayBgm(BgmTypeValue type, bool loop)
        {
            AudioClip clip = _soundClips.GetBgmClip(type);
            if (clip != null)
            {
                PlayBgm(clip, loop);
            }
        }
        
        public void PlayBgm(AudioClip clip, bool loop)
        {
            if (clip != null)
            {
                _bgmAudioPlayer.loop = loop;
                _bgmAudioPlayer.Play(clip);
            }
        }
        public void StopBgm()
        {
            CheckCoroutines();
            SetBgmVolume();
            _bgmAudioPlayer.Stop();
        }
        public void PauseBgm()
        {
            CheckCoroutines();
            SetBgmVolume();
            _bgmAudioPlayer.Pause();
        }

        public void ResumeBgm()
        {
            CheckCoroutines();
            SetBgmVolume();
            _bgmAudioPlayer.Resume();
        }
        Coroutine _stopCoroutine;
        Coroutine _pauseCoroutine;
        Coroutine _resumeCoroutine;

        private void CheckCoroutines()
        {
            if (_stopCoroutine != null)
            {
                StopCoroutine(_stopCoroutine);
                _stopCoroutine = null;
            }

            if (_pauseCoroutine != null)
            {
                StopCoroutine(_pauseCoroutine);
                _pauseCoroutine = null;
            }

            if (_resumeCoroutine != null)
            {
                StopCoroutine(_resumeCoroutine);
                _resumeCoroutine = null;
            }
        }
        
        public void StopBgm(int rampTime, System.Action callback)
        {
            CheckCoroutines();
            SetBgmVolume();
            _stopCoroutine = StartCoroutine(StopRamp(rampTime, callback));
        }
        
        public void PauseBgm(int rampTime, System.Action callback)
        {
            CheckCoroutines();
            SetBgmVolume();
            _pauseCoroutine = StartCoroutine(PauseRamp(rampTime, callback));
        }
        
        public void ResumeBgm(int rampTime, System.Action callback)
        {
            CheckCoroutines();
            SetBgmVolume();
            _resumeCoroutine = StartCoroutine(ResumeRamp(rampTime, callback));
        }

        IEnumerator StopRamp(int rampTime,System.Action callback)
        {
            if (_bgmAudioPlayer.IsPlaying)
            {
                float rampTimeFloat = rampTime / 1000f;
                float currentTime = 0;
                while (currentTime < rampTimeFloat)
                {
                    _bgmAudioPlayer.volume =
                        _internalVolumeScale * mainVolume * bgmVolume * (1 - currentTime / rampTimeFloat);
                    yield return new WaitForEndOfFrame();
                    currentTime += Time.deltaTime;
                }
                _bgmAudioPlayer.Stop();
                _stopCoroutine = null;
            }
        }

        IEnumerator PauseRamp(int rampTime, System.Action callback)
        {
            if (_bgmAudioPlayer.IsPlaying && !_bgmAudioPlayer.IsPaused)
            {
                float rampTimeFloat = rampTime / 1000f;
                float currentTime = 0;
                while (currentTime < rampTimeFloat)
                {
                    _bgmAudioPlayer.volume =
                        _internalVolumeScale * mainVolume * bgmVolume * (1 - currentTime / rampTimeFloat);
                    yield return new WaitForEndOfFrame();
                    currentTime += Time.deltaTime;
                }

                _bgmAudioPlayer.Pause();
                _pauseCoroutine = null;
            }
        }

        IEnumerator ResumeRamp(int rampTime,System.Action callback)
        {
            if (_bgmAudioPlayer.IsPaused || (!_bgmAudioPlayer.IsPlaying && !_bgmAudioPlayer.IsPaused))
            {
                float rampTimeFloat = rampTime / 1000f;
                float currentTime = 0;
                while (currentTime < rampTimeFloat)
                {
                    _bgmAudioPlayer.volume =
                        _internalVolumeScale * mainVolume * bgmVolume * (currentTime / rampTimeFloat);
                    yield return new WaitForEndOfFrame();
                    currentTime += Time.deltaTime;
                }
                _bgmAudioPlayer.Resume();
                _resumeCoroutine = null;
            }
        }
        
        private void OnApplicationFocus(bool hasFocus)
        {
            if (actionOnFocus)
            {
                if (hasFocus)
                {
                    _internalVolumeScale = 1;
                }
                else
                {
                    _internalVolumeScale = 0.0f;
                }
                _bgmAudioPlayer.volume = _internalVolumeScale * mainVolume * bgmVolume;
                _effectAudioSource.volume = _internalVolumeScale * mainVolume * effectVolume;
            }
        }

        private void OnDestroy()
        {
            if (_instance == this)
            {
                _instance = null;
            }
        }
        
        #if UNITY_EDITOR
        [Button]
        private void StopRamp_UnitTest(int rampTime)
        {
            StopBgm(rampTime, () =>
            {
                Debug.Log("StopRamp_UnitTest Completed");
            });
        }
        #endif
    }
}

